"""
app包的初始化文件中完成以下两步:
    定义工厂函数
    添加 common路径
"""
from flask import Flask
from os.path import *
import sys

# 将common路径加入模块查询路径
BASE_DIR = dirname(dirname(abspath(__file__)))
sys.path.insert(0, BASE_DIR + '/common')

from app.settings.config import config_dict
from utils.constants import EXTRA_ENV_COINFIG
from flask_sqlalchemy import SQLAlchemy
from redis import StrictRedis
from flask_migrate import Migrate
from flask_cors import CORS
from models.routing_db.routing_sqlalchemy import RoutingSQLAlchemy
from rediscluster import RedisCluster


# # 创建sqlalchemy组件对象
# db = SQLAlchemy()

# 使用自定义的SQLAlchemy类
# mysql数据库操作对象
db = RoutingSQLAlchemy()


# 创建redis数据库操作对象
# redis_client = None     # type:StrictRedis
# 创建redis主数据库客户端对象
redis_master = None  # type: StrictRedis
# 创建redis从数据库客户端对象
redis_slave = None  # type: StrictRedis
# 创建集群客户端对象
redis_cluster = None  # type: RedisCluster


def create_flask_app(type):
    """
    创建flask应用
    :param type: 配置类型
    :return: flask应用
    """

    # 创建flask应用
    app = Flask(__name__)
    # 根据配置类型加载配置子类
    config_class = config_dict[type]
    # 先加载默认配置
    app.config.from_object(config_class)
    # 再加载额外配置
    app.config.from_envvar(EXTRA_ENV_COINFIG, silent=True)

    # 返回应用
    return app


# def register_extensions(app:str)
def register_extensions(app:Flask):
    """组件初始化"""

    # sqlalchemy组件初始化,延后关联Flask应用
    db.init_app(app)

    # # redis组件初始化
    # global redis_client
    # redis_client = StrictRedis(host=app.config['REDIS_HOST'], port=app.config['REDIS_PORT'], decode_responses=True)
    # redis集群组件初始化
    global redis_cluster
    redis_cluster = RedisCluster(startup_nodes=app.config['CLUSTER_NODES'], decode_responses=True)

    # 注册添加路由转换器
    from utils.converters import register_converters
    register_converters(app)

    # 数据迁移组件初始化
    Migrate(app, db)

    # 导入模型类文件(让项目发现对应的模型类)
    from models import user, article
    """
    执行数据迁移命令:
        export FLASK_APP=app.main  # 设置环境变量指定启动文件
        flask db init  # 生成迁移文件夹
        flask db migrate  # ⽣成迁移版本, 保存到迁移文件夹中
        flask db upgrade  # 执行迁移
        
    由于数据迁移代码是自动生成的, 为了避免代码合并时出现冲突, 一般不会让git管理迁移文件夹
    将迁移文件夹设置到gitignore文件中进行忽略处理
    """

    # 注册添加请求钩子函数
    from utils.middlewares import get_userinfo
    app.before_request(get_userinfo)

    # Flask组件flask-cors可以处理跨域问题, 安装 pip install flask-cors
    # 配置跨域请求组件初始化
    CORS(app, supports_credentials=True)  # 设置supports_credentials=True, 则允许跨域传输cookie

    # 哨兵客户端
    from redis.sentinel import Sentinel
    global redis_master, redis_slave
    sentinel = Sentinel(app.config['SENTINEL_LIST'])
    # 获取主从数据库对象
    redis_master = sentinel.master_for(app.config['SERVICE_NAME'], decode_responses=True)
    redis_slave = sentinel.slave_for(app.config['SERVICE_NAME'], decode_responses=True)


def register_bp(app:Flask):
    """注册蓝图"""
    # 进行局部导入, 避免组件没有初始化完成
    from app.resources.user import user_bp
    app.register_blueprint(user_bp)

    from app.resources.article import article_bp
    app.register_blueprint(article_bp)


def create_app(type):
    """创建flask应用 和 组件初始化"""

    # 创建flask应用
    app = create_flask_app(type)
    # 组件初始化
    register_extensions(app)

    # 注册蓝图
    register_bp(app)

    return app
